package com.pan.games.threadgame.communicate;

/**
 * @author by panstark
 * @description
 * @notice
 * @date 2020/12/15
 */

import lombok.extern.slf4j.Slf4j;

import java.util.ArrayList;
import java.util.List;

/**
 * 当一个变量定义为 volatile 之后，将具备两种特性：
 * 　　1.保证此变量对所有的线程的可见性，这里的“可见性”，
 *       当一个线程修改了这个变量的值，volatile 保证了新值能立即同步到主内存，以及每次使用前立即从主内存刷新。
 *       但普通变量做不到这点，普通变量的值在线程间传递均需要通过主内存（详见：Java内存模型）来完成。
 * 　　2.禁止指令重排序优化。
 *      有volatile修饰的变量，赋值后多执行了一个“load addl $0x0, (%esp)”操作，这个操作相当于一个内存屏障（指令重排序时不能把后面的指令重排序到内存屏障之前的位置），只有一个CPU访问内存时，并不需要内存屏障；（什么是指令重排序：是指CPU采用了允许将多条指令不按程序规定的顺序分开发送给各相应电路单元处理）。
 *
 * volatile 性能：
 * 　　volatile 的读性能消耗与普通变量几乎相同，但是写操作稍慢，因为它需要在本地代码中插入许多内存屏障指令来保证处理器不发生乱序执行。
 */
public class ShareCommunicate {

    /*
     *可以试着去掉 volatile 来观察打印you和诺不同
     */
    // 定义一个共享变量来实现通信，它需要是volatile修饰，否则线程不能及时感知
    public static volatile boolean volatileNotice = false;

    public static boolean commonNotice=false;

    public static void main(String[] args) {

        Thread changeThread = new ShareCommunicateChangeThread();
        Thread receiveThread = new ShareCommunicateReceiveThread();

        receiveThread.start();
        changeThread.start();

    }
}


class ShareCommunicateChangeThread extends Thread {

    List<String> list = new ArrayList<>();
    @Override
    public void run(){

        for (int i = 1; i <= 10; i++) {
            list.add("abc");
            System.out.println("线程:"+currentThread().getName()+"向list中添加一个元素，此时list中的元素个数为：" + list.size());
            try {
                Thread.sleep(500);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            if (list.size() == 5) {
                ShareCommunicate.volatileNotice = true;
                ShareCommunicate.commonNotice = true;
                System.out.println("volatileNotice:"+ ShareCommunicate.volatileNotice);
                System.out.println("commonNotice:"+ ShareCommunicate.commonNotice);
            }
        }
    }
}

@Slf4j
class ShareCommunicateReceiveThread extends Thread{

    private long startTime = System.currentTimeMillis();
    //覆盖Thread类中的run方法.
    @Override
    public void run() {

        while(true){

            if(ShareCommunicate.volatileNotice){
                System.out.println(currentThread().getName()+"已经收到了volatileNotice");
                break;
            }
        }

        while(true){

            if(ShareCommunicate.commonNotice){
                System.out.println(currentThread().getName()+"已经收到了commonNotice");
                break;
            }

            long currentTimeMillis = System.currentTimeMillis();
            boolean off= currentTimeMillis-startTime>1000*60;
            if(off){
                System.out.println(currentThread().getName()+"没有收到commonNotice但是超时了");
                break;
            }
        }

    }
}
